package com.hanc.pay.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.hanc.pay.config.WxPayConfig;
import com.hanc.pay.entity.OrderInfo;
import com.hanc.pay.entity.Product;
import com.hanc.pay.entity.RefundInfo;
import com.hanc.pay.enums.OrderStatus;
import com.hanc.pay.enums.wxpay.WxApiType;
import com.hanc.pay.enums.wxpay.WxNotifyType;
import com.hanc.pay.enums.wxpay.WxRefundStatus;
import com.hanc.pay.mapper.OrderInfoMapper;
import com.hanc.pay.mapper.ProductMapper;
import com.hanc.pay.mapper.RefundInfoMapper;
import com.hanc.pay.service.WxPayService;
import com.hanc.pay.util.OrderNoUtils;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
    @Resource
    private WxPayConfig wxPayConfig;
    @Resource
    private ProductMapper productMapper;
    @Resource
    private OrderInfoMapper orderInfoMapper;
    @Resource
    private CloseableHttpClient httpClient;
    @Resource
    private RefundInfoMapper refundInfoMapper;

    @Override
    public Map<String, Object> nativePay(Long productID) throws Exception {
        log.info("支付下单");
        Product product = productMapper.selectById(productID);

        //查询当前商品是否有未支付订单
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_id",productID);
//        queryWrapper.eq("user_id",userID);
        queryWrapper.eq("order_status",OrderStatus.NOTPAY.getType());
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);

        if (orderInfo != null && !StringUtils.isEmpty(orderInfo.getCodeUrl())){
            //返回二维码与订单号
            Map<String, Object> map = new HashMap<>();
            map.put("codeUrl",orderInfo.getCodeUrl());
            map.put("orderNo",orderInfo.getOrderNo());
            return map;
        }else {
            orderInfo = new OrderInfo(
                    product.getTitle(),
                    OrderNoUtils.getOrderNo(),
                    new Long(1),  //userID用户ID
                    productID,
                    product.getPrice(),
                    OrderStatus.NOTPAY.getType()
            );
            orderInfoMapper.insert(orderInfo);
        }


        log.info("调用统一支付下单API");
        //构造请求体数据
        HashMap<String,Object> reqData=new HashMap<>();
        reqData.put("appid",wxPayConfig.getAppid());
        reqData.put("mchid",wxPayConfig.getMchId());
        reqData.put("description",orderInfo.getTitle());
        reqData.put("out_trade_no",orderInfo.getOrderNo());
        reqData.put("notify_url","wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType())");
        HashMap<String,Integer> amount=new HashMap<>();
        //单位是分
        amount.put("total",orderInfo.getTotalFee());
        reqData.put("amount",amount);
        String jsonReqData=new Gson().toJson(reqData);
        log.info("下单请求参数",jsonReqData);

        //请求头构造
        HttpPost httpPost=new HttpPost(wxPayConfig.getDomain()+ WxApiType.NATIVE_PAY);
        StringEntity entity=new StringEntity(jsonReqData,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept","application/json");
        log.info("构造请求头信息结束");

        // 调用下单方法，得到应答
        CloseableHttpResponse response = httpClient.execute(httpPost);
        log.info("调用统一支付下单结束",response.toString());

        Map<String,String> dataMap=null;
        try{
            int statusCode=response.getStatusLine()
                    .getStatusCode();
            //成功
            if(statusCode < 400){
                String body=EntityUtils.toString(response.getEntity());
                dataMap=new Gson().fromJson(body,HashMap.class);
                //存储订单支付二维码
                orderInfo.setCodeUrl(dataMap.get("code_url"));

                QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
                wrapper.eq("order_no",orderInfo.getOrderNo());
                orderInfoMapper.update(orderInfo,wrapper);
            }
            //失败
            else{
                if(statusCode != 204){
                    String body=EntityUtils.toString(response.getEntity());
                    log.error(body);
                    return null;
                }
            }
        }
        finally{
            response.close();
        }
        //返回二维码与订单号
        Map<String, Object> map = new HashMap<>();
        map.put("codeUrl",dataMap.get("code_url"));
        map.put("orderNo",orderInfo.getOrderNo());
        return map;
    }

    @Override
    public void closeNativePay(String orderNo) throws Exception {
        //查询当前订单状态是否是未支付
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no",orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        if (orderInfo == null || !orderInfo.getOrderStatus().equals(OrderStatus.NOTPAY.getType())){
            log.error("查询当前订单异常或订单状态异常");
        }

        //url地址
        String url = String.format(WxApiType.CLOSE_ORDER_BY_NO.getType(), orderNo);
        url = wxPayConfig.getDomain().concat(url);
        HttpPost httpPost = new HttpPost(url);

        //请求参数设置
        Map<String, String> map = new HashMap<>();
        map.put("mchid",wxPayConfig.getMchId());
        String jsonData = new Gson().toJson(map);

        //请求头设置
        StringEntity entity=new StringEntity(jsonData,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept","application/json");
        log.info("构造请求头信息结束");

        CloseableHttpResponse response = null;
        try{
            //完成签名并执行请求
            response = httpClient.execute(httpPost);
            Map<String,String> dataMap=null;
            int statusCode = response.getStatusLine()
                    .getStatusCode();
            //成功
            if(statusCode == 204){
                log.info("取消订单{}成功",orderNo);
                //修改订单状态
                orderInfo.setOrderStatus(OrderStatus.CANCEL.getType());
                orderInfoMapper.updateById(orderInfo);
            }
            //失败
            else{
                log.error("取消订单{}失败,失败状态码{}",orderNo,statusCode);
            }
        }
        catch(Exception e){
            log.error("取消订单{}失败",orderNo);
        }
        finally{
            try{
                response.close();
            }
            catch(IOException e){
                log.error("关闭response失败");
            }
        }

    }

    @Override
    public String queryOrder(String orderNo) throws Exception {

        String url = String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo);
        url = wxPayConfig.getDomain().concat(url).concat("?mchid=").concat(wxPayConfig.getMchId());

        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept","application/json");

        CloseableHttpResponse response = null;

        try{
            //完成签名并执行请求
            response = httpClient.execute(httpGet);
            Map<String,String> dataMap=null;
            int statusCode = response.getStatusLine()
                    .getStatusCode();
            //成功
            String body=EntityUtils.toString(response.getEntity());
            //成功
            if(statusCode < 400){

                log.info("查询订单支付{}成功",orderNo);
                return body;
            }
            //失败
            else{
                log.error("查询订单支付{}失败,返回数据为{}.",orderNo,body);
                throw new IOException("订单查询失败");
            }
        }finally{
            try{
                response.close();
            }
            catch(IOException e){
                log.error("关闭response失败");
            }
        }



    }

    @Override
    public void refunds(String orderNo, String reason) throws Exception {
        log.info("创建退款订单");

        //查询原始订单
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no", orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        if (orderInfo == null) {
            log.error("查询原始订单失败");
        }

        //新增退款订单
        RefundInfo info = new RefundInfo(
                orderNo,
                OrderNoUtils.getRefundNo(),
                orderInfo.getTotalFee(),
                orderInfo.getTotalFee(),
                reason
        );
        refundInfoMapper.insert(info);


        Map<String, Object> map = new HashMap<>();
        map.put("out_refund_no ", orderNo);
        map.put("out_refund_no", info.getRefundNo());
        map.put("reason", reason);
        map.put("notify_url", wxPayConfig.getDomain().concat(WxNotifyType.REFUND_NOTIFY.getType()));
        Map<String, Object> amountMap = new HashMap<>();
        amountMap.put("refund ", info.getRefund());
        amountMap.put("total ", info.getTotalFee());
        amountMap.put("currency", "CNY");
        map.put("amount", amountMap);

        String jsonData = new Gson().toJson(map);
        log.info("请求参数===>{}",jsonData);

        String url = wxPayConfig.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType());
        HttpPost httpPost = new HttpPost(url);

        //请求头设置
        StringEntity entity = new StringEntity(jsonData, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        CloseableHttpResponse response = null;
        try {
            //完成签名并执行请求
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine()
                    .getStatusCode();
            //成功
            String body = EntityUtils.toString(response.getEntity());
            //成功
            if (statusCode < 400) {
                log.info("成功, 退款返回结果 ={} ",body);

            }
            //失败
            else {
                log.error("查询订单支付{}失败,返回数据为{}.", orderNo, body);
                throw new IOException("订单查询失败");
            }

            //更新订单状态
            orderInfo.setOrderStatus(OrderStatus.REFUND_PROCESSING.getType());
            orderInfoMapper.updateById(orderInfo);

            Map<String,String> bodyMap = new Gson().fromJson(body, HashMap.class);
            String refundId = bodyMap.get("refund_id");
            info.setRefundId(refundId);
            if (bodyMap.get("status") != null){
                info.setRefundStatus(bodyMap.get("status"));
            }
            if (bodyMap.get("refund_status") != null){
                info.setRefundStatus(bodyMap.get("refund_status"));
            }
            //将下单返回参数存入数据库
            info.setContentReturn(body);
            refundInfoMapper.updateById(info);

        } finally {
            try {
                response.close();
            } catch (IOException e) {
                log.error("关闭response失败");
            }


        }
    }
}
